package com.cskaoyan.javase.homework.day20;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Random;

/**
 * 要求: 从0-9这10个数中
 * - 生成一个长度是3的随机数字，把这个字符串当作密码
 * 012,123,900,666....
 * 这个密码应该当成字符串处理,以后开发中处理数字,小数等都建议优先考虑用字符串处理
 * - 创建一个破解线程，使用穷举法，匹配这个密码,直到匹配到正确的
 * - 创建一个日志线程，将用过的字符串写入文件，这个日志线程设计为守护线程
 * 提示：
 * 破解线程把穷举法生成的可能密码放在一个容器中，这个容器存储匹配过程中用到的密码。
 * 容器中存储的最后一个字符串就是正确的密码
 * 日志线程把这个容器中的密码并打印出来。(因为没有学集合,先用数组)
 * 注意:  守护线程的特征,jvm中只有守护线程 jvm退出
 *
 * @since 09:26
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    private static String pwd;
    private static String[] pwds = new String[1000];
    private static int pwdIndex;

    public static void main(String[] args) {
        // 随机生成一个密码
        pwd = creatPwdStringRandom();
        System.out.println("随机生成的密码是:" + pwd);

        Thread matchThread = new Thread(Demo::match, "破解密码线程");
        matchThread.start();
        try {
            matchThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 这个代码写在主线程里,主线程和破解线程是并发执行的,所以这里打印的时候,破解线程还没有来得及去赋值数组
        // 所以这里如果希望能够看到破解线程赋值数组的结果,应该让破解线程先执行完毕,然后再执行主线程的这行代码
        System.out.println(Arrays.toString(pwds));

        // 继续执行守护线程打印日志
        Thread logThread = new Thread(Demo::printLog, "日志打印线程");
        // 当进场中只有守护线程时,进程就会关闭,Java程序就结束了
        logThread.setDaemon(true);
        logThread.start();

        // 需要让主线程休眠,让日志线程有时间去打印日志
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void printLog() {
        //  创建一个日志线程，将用过的字符串写入文件，打印匹配的过程,然后打印密码的最终结果
        try (PrintWriter writer = new PrintWriter(new FileWriter("log.txt"))) {
            // 将pwds数组内的匹配过程打印到文件中
            for (int i = 0; i < pwds.length; i++) {
                /*if (i < findPwdIndex()) {
                    // 是匹配密码的过程
                    writer.println("尝试匹配密码:" + pwds[i] + "......匹配失败,不是密码");
                }
                if (i == findPwdIndex()) {
                    // 是密码
                    writer.println("尝试匹配密码:" + pwds[i] + "......匹配成功,它就是密码!");
                    break;
                }*/

                if (i < pwdIndex) {
                    // 是匹配密码的过程
                    writer.println("尝试匹配密码:" + pwds[i] + "......匹配失败,不是密码");
                }
                if (i == pwdIndex) {
                    // 是密码
                    writer.println("尝试匹配密码:" + pwds[i] + "......匹配成功,它就是密码!");
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static int findPwdIndex() {
        for (int i = 0; i < pwds.length; i++) {
            if (pwd.equals(pwds[i])) {
                return i;
            }
        }
        return -1;
    }

    // 该方法用于穷举匹配密码,将匹配的过程以及最终的密码存入一个容器,该方法还会返回密码在容器中的下标
    private static void match() {
        // 穷举破解
        for (int i = 0; i < 1000; i++) {
            // 对于一个整数0,如何变成000?
            String match = String.format("%03d", i);
            // System.out.println(match);
            // 匹配过程的密码全部装入数组中
            if (!match.equals(pwd)) {
                // 不是密码 装入容器
                pwds[i] = match;
                System.out.println(pwds[i]);
            }
            if (match.equals(pwd)) {
                // 密码匹配正确了,也装到这个容器里,这时它是容器中最后一个字符串,从这个密码字符串以后都是null
                pwds[i] = match;
                // 将密码的存储下标赋值存起来
                pwdIndex = i;
                System.out.println(pwds[i]);
                break;
            }
        }
    }

    // 返回一个随机生成的三位数字密码
    private static String creatPwdStringRandom() {
        // 生成一个三位的随机数字符串
        char[] pwd = new char[3];
        String str = "0123456789";
        Random random = new Random();
        //[0,999)
        int randomNum = random.nextInt(1000);
        return String.format("%03d", randomNum);
        /*for (int i = 0; i < pwd.length; i++) {
            // String charAt(index) index需要随机生成
            // nextInt()无参的[0,1] 如果有参数就乘以
            // [0,str.length-1]
            int index = random.nextInt(str.length());
            // 获取随机下标的一个数字
            char randomNum = str.charAt(index);
            pwd[i] = randomNum;
        }
        return new String(pwd);*/
    }
}
